#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os, stat
import pygtk
pygtk.require('2.0')
import gtk, pango
import gtk.glade

APP_NAME = 'MOM-CHENG'
LOCALE_DIR = 'locale'

WORD_WIDTH = 16
CN_NG = u"〇"
NXT_WORD = u'^'

(PG_LESSION, PG_REVFIND, PG_WELCOME) = range(3)

if os.path.islink(__file__):
    this_file = os.readlink(__file__)
else:
    this_file = __file__
APP_DIR = os.path.realpath(os.path.dirname(this_file))

gtk.glade.bindtextdomain(APP_NAME, LOCALE_DIR)
gtk.glade.textdomain(APP_NAME)

# RCFILE = os.path.join(os.path.realpath(os.path.dirname(this_file)), 'gtk', 'gtkrc')
# gtk.rc_parse(RCFILE)

LESSIONS = os.path.join(os.path.realpath(os.path.dirname(this_file)), 'lessions')

class MainWindow:
    def __on_combobox_lession_changed(self, combobox):
        model = combobox.get_model()
        iter = combobox.get_active_iter()
        if iter:
            lession = model[iter][1]
            self.__notebook_main.set_current_page(PG_LESSION)

            if os.path.isfile(lession):
                f = open(lession)
                # First Line is the description, which \n converted to \\n
                # Lines begin from 2 is char-code pair

                self.__lession_desc = f.readline().replace('\\n', '\n')[1:]
                pairs = f.read().replace('\n', ' ').split()
                wlist = []
                for i in range(0, len(pairs), 2):
                    wlist.append([unicode(pairs[i+1]), unicode(pairs[i])])

                self.__nb_lesson_change(wlist)
                f.close()

    def __on_tbar_revfind_toggled(self, button):
        if button.get_active():
            self.__notebook_main.set_current_page(PG_REVFIND)
        else:
            self.__notebook_main.set_current_page(PG_LESSION)
            self.__entry_input.grab_focus()

    def __walk_and_fill_lessions(self, path, parent=None):
        for f in os.listdir(path):
            if not f.startswith("."):
                fullname = os.path.join(path, f)
                fdata = os.stat(fullname)
                is_folder = stat.S_ISDIR(fdata.st_mode)
                li = self.__tbar_lessions_combobox_treestore.append(parent, [f, os.path.join(path, f), is_folder])
                if is_folder:
                    self.__walk_and_fill_lessions(fullname, li)

    def __setup_lessions(self):
        self.__tbar_lessions_combobox_treestore = gtk.TreeStore(str, str, bool)

        # fill lession by scan the LESSIONS dir
        self.__walk_and_fill_lessions(LESSIONS)

        combo_store = self.__tbar_lessions_combobox_treestore.filter_new()
        #combo_store.set_visible_func(lambda model, iter: model[iter][3])

        self.__combobox_lessions.set_model(combo_store)

        combo_cell_text = gtk.CellRendererText()
        self.__combobox_lessions.pack_start(combo_cell_text, True)
        self.__combobox_lessions.add_attribute(combo_cell_text, "text", 0)

        self.__combobox_lessions.connect('changed', self.__on_combobox_lession_changed)

    def __scroll_if_needed(self):
        self.__input_label_pango_layout.set_text(self.__label_wei.get_text()[:-1])
        tw, th = self.__input_label_pango_layout.get_pixel_size()

        def ensureVisible(adjustment, position):
            vis_lo = adjustment.value
            vis_pg = adjustment.page_size - 24
            vis_hi = adjustment.value + vis_pg

            if position <= vis_lo or position >= vis_hi:
                desired = position - vis_pg / 2
                if desired < 0:
                    desired = 0
                elif desired + vis_pg >= adjustment.upper:
                    desired = adjustment.upper - vis_pg
                adjustment.set_value(desired)

        ensureVisible(self.__scrolledwindow_lession.get_hadjustment(), tw)

    def __on_lesson_input_key_press(self, widget, key):
        input = self.__entry_input.get_text().strip()
        self.__entry_input.set_text(input)

        if input and (key.keyval == gtk.keysyms.space or key.keyval == gtk.keysyms.Return):
            # search the words according to input text

            cn_ok = self.__chars[self.__chars_index]
            en_ok = self.__wdict[cn_ok]

            if input.lower() in en_ok.lower().split(','):
                append_char = cn_ok
            else:
                append_char = CN_NG * len(cn_ok)
                self.__fails.append([cn_ok, en_ok])

            input_label_text = self.__label_wei.get_text()[:-1]
            input_label_text += append_char + u' ' + NXT_WORD
            self.__label_wei.set_text(input_label_text)

            self.__scroll_if_needed()

            self.__chars_index += 1

            self.__entry_input.set_text('')
            self.__show_input_hint()
            self.__update_status()

            if self.__chars_index + 1 > self.__chars_count:
                self.__entry_input.set_sensitive(False)
                self.__retry_fails()

    def __retry_fails(self):
        if self.__fails:
            # show try fails
            dlg = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO)
            dlg.set_markup('<big><b>%s</b></big>' % 'Warning')
            dlg.format_secondary_markup('Lession is not passed, %d fails, retry the fails?' % len(self.__fails))
            dlg.set_default_response(gtk.RESPONSE_YES)

            if dlg.run() == gtk.RESPONSE_YES:
                self.__nb_lesson_change(self.__fails)
            dlg.destroy()

    def __update_status(self):
        text = '%d/%d, NG:%d' % (self.__chars_index, self.__chars_count, len(self.__fails))
        self.__label_stat.set_text(text)

    def __show_input_hint(self):
        if self.__nb_lesson_input_hint:
            if self.__chars_index + 1 <= self.__chars_count:
                self.__entry_hint.set_text(unicode(self.__codes[self.__chars_index]))
        else:
            self.__entry_hint.set_text('')

    def __on_lesson_input_hint_clicked(self, widget):
        self.__nb_lesson_input_hint = widget.get_active()
        self.__show_input_hint()
        self.__entry_input.grab_focus()

    def __create_lession_notebook_page(self):
        self.__lession_desc = ''
        self.__nb_lesson_input_hint = False

        self.__input_label_pango_ctx = self.__label_wei.get_pango_context()
        self.__input_label_pango_layout = pango.Layout(self.__input_label_pango_ctx)

        self.__label_tmp_pango_ctx = self.__label_wei.get_pango_context()
        self.__label_tmp_pango_layout = pango.Layout(self.__label_tmp_pango_ctx)

        self.__nb_lesson_change({})

    def __nb_lesson_change(self, wlist):
        '''
        Update the ui for new lession content. for the content file, line one is the chinese,
        line two is acording chars. Each word is separted by a space

        wlist: a RIGHT list which already strip non-letters and non-chinese
        '''
        if not wlist:
            return

        self.__wdict = {}
        self.__chars = []
        self.__codes = []
        self.__fails = []

        for i in wlist:
            cn, en = i
            self.__wdict[cn] = en
            self.__chars.append(cn)
            self.__codes.append(en)

        self.__chars_count = len(self.__chars)
        self.__chars_index = 0

        self.__label_tou.set_text(' '.join(self.__chars))
        self.__label_wei.set_text(NXT_WORD)
        self.__show_input_hint()
        self.__update_status()
        self.__entry_input.set_sensitive(True)
        self.__scrolledwindow_lession.get_hadjustment().set_value(0)

        self.__textview_desc.get_buffer().set_text(self.__lession_desc)

        self.__entry_input.grab_focus()

    def __init__(self):
        self.__load_glade_window()
        self.__connect_signals()
        self.__adjust_glade_window()

        self.__create_lession_notebook_page()
        self.__setup_lessions()

        self.__show()

    def __load_glade_window(self):
        glade = os.path.join(APP_DIR, 'main.glade')
        self.__glade = gtk.glade.XML(glade, domain=APP_NAME)

        self.__label_stat = self.__glade.get_widget('label_stat')
        self.__entry_input = self.__glade.get_widget('entry_input')
        self.__entry_hint = self.__glade.get_widget('entry_hint')
        self.__checkbutton_hint = self.__glade.get_widget('checkbutton_hint')
        self.__textview_desc = self.__glade.get_widget('textview_desc')
        self.__label_wei = self.__glade.get_widget('label_wei')
        self.__eventbox_wei = self.__glade.get_widget('eventbox_wei')
        self.__label_tou = self.__glade.get_widget('label_tou')
        self.__eventbox_tou = self.__glade.get_widget('eventbox_tou')
        self.__togglebutton_reverse_find = self.__glade.get_widget('togglebutton_reverse_find')
        self.__combobox_lessions = self.__glade.get_widget('combobox_lessions')
        self.__window_main = self.__glade.get_widget('window_main')
        self.__notebook_main = self.__glade.get_widget('notebook_main')
        self.__scrolledwindow_lession = self.__glade.get_widget('scrolledwindow_lession')
        self.__label_tooltip = self.__glade.get_widget('label_tooltip')
        self.__button_reload = self.__glade.get_widget('button_reload')

        self.__label_tmp = self.__glade.get_widget('label_tmp')

    def __adjust_glade_window(self):
        self.__label_tou.modify_font(pango.FontDescription("sans %d" % WORD_WIDTH))
        self.__label_wei.modify_font(pango.FontDescription("sans %d" % WORD_WIDTH))
        self.__label_tmp.modify_font(pango.FontDescription("sans %d" % WORD_WIDTH))

    def __loc_words_index(self, x):
        cursor_pos = self.__scrolledwindow_lession.get_hadjustment().value + x
        cursor_pos = x

        #print 'value: ', self.__scrolledwindow_lession.get_hadjustment().value
        #print 'x: ', x
        #print 'cursor_pos: ', cursor_pos

        tmp_text = ''
        for i in range(0, self.__chars_count):
            tmp_text += self.__chars[i] + u' '
            self.__label_tmp.set_text(tmp_text)
            self.__label_tmp_pango_layout.set_text(tmp_text)
            tw, th = self.__label_tmp_pango_layout.get_pixel_size()
            if tw > cursor_pos:
                break

        return i

    def __fast_jump(self, index):
        if index > self.__chars_index:
            input_label_text = self.__label_wei.get_text()[:-1]
            for j in range(0, index - self.__chars_index):

                cn_ok = self.__chars[self.__chars_index]
                en_ok = self.__wdict[cn_ok]

                append_char = CN_NG * len(cn_ok)
                self.__fails.append([cn_ok, en_ok])

                input_label_text += append_char + u' '
                self.__label_wei.set_text(input_label_text)

                self.__chars_index += 1

            input_label_text += NXT_WORD
            self.__label_wei.set_text(input_label_text)

        self.__show_input_hint()
        self.__update_status()

    def __fast_hint(self, index):
        text = self.__chars[index] + ':' + self.__codes[index]
        self.__label_tooltip.set_text(text)

    def __on_workarea_button_press(self, button, event):
        if event.button == 3:
            i = self.__loc_words_index(event.x)
            self.__fast_hint(i)
        elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
            i = self.__loc_words_index(event.x)
            self.__fast_jump(i)

    def __on_workarea_button_release(self, button, event):
        self.__label_tooltip.set_text('')

    def __on_reload_button_clicked(self, widget):
        self.__chars_index = 0

        self.__label_tou.set_text(' '.join(self.__chars))
        self.__label_wei.set_text(NXT_WORD)
        self.__show_input_hint()
        self.__update_status()
        self.__scrolledwindow_lession.get_hadjustment().set_value(0)

    def __connect_signals(self):
        self.__window_main.connect('destroy', lambda w: gtk.main_quit())

        self.__entry_input.connect('key-press-event', self.__on_lesson_input_key_press)
        self.__checkbutton_hint.connect("clicked", self.__on_lesson_input_hint_clicked)
        self.__togglebutton_reverse_find.connect('toggled', self.__on_tbar_revfind_toggled)
        self.__combobox_lessions.connect('changed', self.__on_combobox_lession_changed)

        self.__button_reload.connect('clicked', self.__on_reload_button_clicked)

        self.__eventbox_tou.connect('button-press-event', self.__on_workarea_button_press)
        self.__eventbox_wei.connect('button-press-event', self.__on_workarea_button_press)
        self.__eventbox_tou.connect('button-release-event', self.__on_workarea_button_release)
        self.__eventbox_wei.connect('button-release-event', self.__on_workarea_button_release)

    def __show(self):
        self.__window_main.show_all()

def main():
    gtk.main()
    return 0

if __name__ == "__main__":
    MainWindow()
    main()
